﻿/**
  *FileName:    zeigen
  *Date:        23/3/26 周日 上午 11:44:08
  *Author:      Zhou Hang
  *Version:     1.0
  *Description: 对eigen的模仿实现
*/
#include "zeigen.h"

namespace ZEigen {
MatrixXf::MatrixXf(std::vector<std::vector<float> > m) {
	this->r = m.size();
	this->c = m[0].size();  // 有些简单粗暴, 这里可能会出问题
	this->m = m;
}

MatrixXf MatrixXf::operator*(const MatrixXf& m2) {
	if (this->c == m2.r) {
		std::vector<std::vector<float> > ret(this->r, std::vector<float>(m2.c, 0));
		for (int k = 0; k < m2.c; k++) {
			for (int i = 0; i < this->r; i++) {
				float ans = 0;
				for (int j = 0; j < this->c; j++) {
					ans += this->m[i][j] * m2.m[j][k];
				}
				ret[i][k] = ans;
			}
		}
		return MatrixXf(ret);
	}
	else {
		throw std::runtime_error("错误的矩阵乘法");
	}
}

void MatrixXf::setItem(int x, int y, float item)
{
	assert(x >= 0 && x < 2 && y >= 0 && y < 2);
	this->m[x][y] = item;
}

std::ostream& operator<<(std::ostream& out, MatrixXf& m)
{
	int row = m.getRow();
	int col = m.getCol();
	for (int i = 0; i < row; i++) {
		if (i == 0) out << "┍ ";
		else if (i == row - 1) out << "┕ ";
		else out << "│ ";
		for (int j = 0; j < col; j++) {
			out << std::setw(ZEIGEN_OUT_WIDTH) << m.getItem(i, j) << " ";
		}
		if (i == 0) out << "┑";
		else if (i == row - 1) out << "┙ ";
		else out << "│ ";
		out << "\n";
	}
	return out;
}

VectorXf VectorXf::operator*(MatrixXf& m) {
	if (this->getCol() == m.getRow()) {
		std::vector<float> ret(m.getCol(), 0);
		for (int k = 0; k < m.getCol(); k++) {
			float ans = 0;
			for (int j = 0; j < this->getCol(); j++) {
				ans += this->getItem(j) * m.getItem(j, k);
			}
			ret[k] = ans;
		}
		return VectorXf(ret);
	}
	else {
		throw std::runtime_error("错误的矩阵乘法");
	}
}

std::ostream& operator<<(std::ostream& out, VectorXf& v)
{
	int col = v.getRow();
	out << "[ ";
	for (int j = 0; j < col; j++) {
		out << v.getItem(j) << " ";
	}
	out << "]\n";
	return out;
}

/* ====================== 无效矩阵 ====================== */
Empty3f::Empty3f()
{
	std::vector<std::vector<float> > v = {
		{1, 0, 0},
		{0, 1, 0},
		{0, 0, 1}
	};
	MatrixXf::setMatrix(v);
}

/* ====================== 旋转矩阵 ====================== */
Rotate3f::Rotate3f(int angle, int cx, int cy)
{
	float radius = angle * M_PI / 180.0;
	float s = sin(radius);
	float c = cos(radius);
	// T(c)R(angle)T(-c)
	std::vector<std::vector<float> > v = {
		{c, -s, cx * (1 - c) + cy * s},
		{s, c, -cx * s + cy * (1 - c)},
		{0, 0, 1}
	};
	MatrixXf::setMatrix(v);
}

/* ====================== 缩放矩阵 ====================== */
Scale3f::Scale3f(float sx, float sy)
{
	std::vector<std::vector<float> > v = {
		{sx, 0, 0},
		{0, sy, 0},
		{0, 0, 1}
	};
	MatrixXf::setMatrix(v);
}

/* ====================== 平移矩阵 ====================== */
Translation3f::Translation3f(int tx, int ty)
{
	std::vector<std::vector<float> > v = {
		{1, 0, float(tx)},
		{0, 1, float(ty)},
		{0, 0, 1}
	};
	MatrixXf::setMatrix(v);
}

/* ====================== 对称矩阵 ====================== */
// TODO: 这里对称矩阵的实现有点问题，坐标系错误，暂时不想解决了
Symmetry3f::Symmetry3f(float A, float B, float C)
{
	constructorHelper(A, B, C);
}

Symmetry3f::Symmetry3f(POINT start, POINT end)
{
#ifdef TRANSFORMDEBUG
	// 将对称的线绘制出来
	line(start.x, start.y, end.x, end.y);
#endif
	constructorHelper(start.y - end.y, start.x - end.x, (start.x * end.y - start.y * end.x));
}

void Symmetry3f::constructorHelper(float A, float B, float C)
{
	float alpha = 2 * atan(-A / B);
	float c = cos(alpha);
	float s = sin(alpha);
	float delta = C / A;
	std::vector<std::vector<float> > v = {
		{c, s, (c - 1) * delta},
		{s, -c, s * delta},
		{0, 0, 1}
	};
	MatrixXf::setMatrix(v);
}

/* ====================== 常用变换操作 ====================== */
MatrixXf ComposingTransform(std::initializer_list<MatrixXf> matrixes)
{
	MatrixXf ret = static_cast<MatrixXf>(Empty3f());
	for (auto matrix = matrixes.begin(); matrix != matrixes.end(); matrix++) {
		MatrixXf temp = *matrix;
		ret = temp * ret;
		//std::cout << temp << std::endl;
	}
	return ret;
}

POINT TransformPoint(MatrixXf trans, POINT p)
{
	MatrixXf res = trans * VectorXf(p);
	return { static_cast<LONG>(res.getItem(0, 0)), static_cast<LONG>(res.getItem(1, 0)) };
}

POINT TransformPoint(std::initializer_list<MatrixXf> matrixes, POINT p)
{
	MatrixXf trans = ComposingTransform(matrixes);
	return TransformPoint(trans, p);
}

std::vector<POINT> TransformPoints(MatrixXf trans, std::vector<POINT> ps)
{
	std::vector<POINT> ret;
	for (auto p : ps) {
		ret.push_back(TransformPoint(trans, p));
	}
	return ret;
}

std::vector<POINT> TransformPoints(std::initializer_list<MatrixXf> matrixes, std::vector<POINT> ps)
{
	std::vector<POINT> ret;
	for (auto p : ps) {
		ret.push_back(TransformPoint(matrixes, p));
	}
	return ret;
}

std::vector<POINT> SeqTransformPoint(MatrixXf trans, int times, POINT p)
{
	std::vector<POINT> ret;
	ret.push_back(p);
	while (times--) {
		p = TransformPoint(trans, p);
		ret.push_back(p);
	}
	return ret;
}

/* ====================== ZEigen Namespace ====================== */
}

